package com.kasax.plugin.app.transform

import com.android.build.api.transform.*
import com.android.build.gradle.internal.pipeline.TransformManager
import com.android.utils.FileUtils
import com.kasax.plugin.app.LogUtils
import com.kasax.plugin.app.javassist.MyToastInjectByJavassist
import org.apache.commons.codec.digest.DigestUtils
import org.gradle.api.Project

/**
 * 自定插桩
 *
 * https://juejin.cn/post/6844903891138674696?share_token=a8d286f5-415a-4c20-b979-fd8bd0b8c32f
 */
class InjectTransform extends Transform {
    Project project

    InjectTransform(Project proj) {
        this.project = proj
    }

    // 设置我们自定义的Transform对应的Task名称
    // 类似：transformClassesWithPreDexForXXX
    // 这里应该是：transformClassesWithInjectTransformForxxx
    @Override
    String getName() {
        return "InjectTransform"
    }


    @Override
    Set<QualifiedContent.ContentType> getInputTypes() {
        return TransformManager.CONTENT_CLASS
    }

    @Override
    Set<? super QualifiedContent.Scope> getScopes() {
        return TransformManager.SCOPE_FULL_PROJECT
    }

    @Override
    boolean isIncremental() {
        return false
    }

    // inputs是传过来的输入流，有两种格式：jar和目录格式
    // outputProvider 获取输出目录，将修改的文件复制到输出目录，必须执行
    @Override
    void transform(Context context, Collection<TransformInput> inputs, Collection<TransformInput> referencedInputs, TransformOutputProvider outputProvider, boolean isIncremental) throws IOException, TransformException, InterruptedException {
        LogUtils.d(getName(), "------------ ------------  transform 开始  ------------ ------------  ")

        // Transform的inputs有两种类型，一种是目录，一种是jar包，要分开遍历
        inputs.each { TransformInput input ->
            // 遍历文件夹
            LogUtils.d(getName(), "handle directoryInputs start...")
            input.directoryInputs.each {
                    // 遍历文件夹
                    //文件夹里面包含的是我们手写的类以及R.class、BuildConfig.class以及R$XXX.class等
                DirectoryInput directoryInput ->
                    // 注入代码
                    LogUtils.d(getName(), "exec injectToast")
                    def sourceFile = directoryInput.file
                    def sourceFilePath = sourceFile.absolutePath
                    MyToastInjectByJavassist.injectToast(sourceFilePath, project)

                    // 获取输出目录
                    def destFile = outputProvider.getContentLocation(directoryInput.name, directoryInput.contentTypes,
                            directoryInput.scopes, Format.DIRECTORY)
                    LogUtils.d(getName(), "sourceFilePath: $sourceFilePath , destFilePath: $destFile.absolutePath")
                    // 将input的目录复制到output指定目录
                    FileUtils.copyDirectory(sourceFile, destFile)
            }
            LogUtils.d(getName(), "handle directoryInputs complete...")
            LogUtils.d(getName(), "handle jarInputs start...")
            //对类型为jar文件的input进行遍历
            input.jarInputs.each {
                    //jar文件一般是第三方依赖库jar文件
                JarInput jarInput ->
                    // 重命名输出文件(同目录copyFile会冲突）
                    def jarFile = jarInput.file
                    def jarName = jarInput.name
                    LogUtils.d(getName(), "jarName: $jarName")
                    def jarPath = jarFile.absolutePath
                    LogUtils.d(getName(), "jarPath: $jarPath")
                    def jarMd5Name = DigestUtils.md5Hex(jarPath)
                    LogUtils.d(getName(), "jarMd5Name: $jarMd5Name")
                    if (jarName.endsWith(".jar")) {
                        jarName = jarName.substring(0, jarName.length() - 4)
                    }
                    LogUtils.d(getName(), "jarFinalName: $jarMd5Name")
                    def destFile = outputProvider.getContentLocation(jarName + jarMd5Name, jarInput.getContentTypes(),
                            jarInput.getScopes(), Format.JAR)
                    LogUtils.d(getName(), "source-jar: $jarPath -> dest-path: $destFile.absolutePath")
                    FileUtils.copyFile(jarFile, destFile)
            }
            LogUtils.d(getName(), "handle jarInputs complete...")
        }
        LogUtils.d(getName(), "------------ ------------  transform 结束  ------------ ------------  ")

    }
}